package com.jrx.anytxn.param.plugins;

import com.jrx.anytxn.common.constant.CommonContants;
import org.apache.ibatis.executor.statement.StatementHandler;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.SqlCommandType;
import org.apache.ibatis.plugin.*;
import org.apache.ibatis.reflection.DefaultReflectorFactory;
import org.apache.ibatis.reflection.MetaObject;
import org.apache.ibatis.reflection.SystemMetaObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import java.lang.reflect.Field;
import java.sql.Connection;
import java.util.Properties;

/**
 * @description: 版本号自增plugin
 * @date: 2019/8/22 17:45
 * @author: zhenghaopu
 */
@Intercepts({
        @Signature(
                type = StatementHandler.class,
                method = "prepare",
                args = {Connection.class, Integer.class}
        )})
@Component
public class RecordVersionNumberPlugin implements Interceptor {
    private static Logger logger = LoggerFactory.getLogger(RecordVersionNumberPlugin.class);

    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        StatementHandler statementHandler = (StatementHandler) invocation.getTarget();
        MetaObject metaObject = MetaObject
                .forObject(statementHandler, SystemMetaObject.DEFAULT_OBJECT_FACTORY, SystemMetaObject.DEFAULT_OBJECT_WRAPPER_FACTORY,
                        new DefaultReflectorFactory());
        //先拦截到RoutingStatementHandler，里面有个StatementHandler类型的delegate变量，其实现类是BaseStatementHandler，然后就到BaseStatementHandler的成员变量mappedStatement
        MappedStatement mappedStatement = (MappedStatement) metaObject.getValue("delegate.mappedStatement");

        BoundSql boundSql = statementHandler.getBoundSql();
        //获取预编译sql
        String sql = boundSql.getSql();
        //判断sql是否是UPDATE语句
        if(mappedStatement.getSqlCommandType()!=SqlCommandType.UPDATE||!sql.toUpperCase().startsWith(SqlCommandType.UPDATE.toString())){
            return invocation.proceed();
        }
        //剔除缓存表
        if(mappedStatement.getResource().contains(CommonContants.CACHE_MAPPING_MAPPER)){
            return invocation.proceed();
        }


        //向sql语句拼接版本号字段 要注意处理批处理update
        String[] updateStrArr = sql.split(";");
        StringBuilder newString =new StringBuilder();
        for(int i = 0;i<updateStrArr.length;i++){
            String updateStr = updateStrArr[i];
            int wherePos=!updateStr.contains(CommonContants.WHERE)?updateStr.indexOf(CommonContants.LOWWOR_WHERE):
                    updateStr.indexOf(CommonContants.WHERE);
            if(wherePos<1){
                return  invocation.proceed();
            }
            String preSql=updateStr.substring(0,wherePos);
            newString.append(preSql).append(" ,record_version_number=record_version_number+1 ").append(updateStr.substring(wherePos));
            //最后面不加分号
            if(i!=updateStr.length()-1){
                newString.append(";");
            }
        }

        //通过反射修改sql语句
        Field field = boundSql.getClass().getDeclaredField("sql");
        field.setAccessible(true);
        field.set(boundSql, newString.toString());
        return invocation.proceed();
    }
    @Override
    public Object plugin(Object target) {
        if (target instanceof StatementHandler) {
            return Plugin.wrap(target, this);
        } else {
            return target;
        }
    }
    @Override
    public void setProperties(Properties properties) {
        logger.debug("设置参数，可以为空");
    }

}
